#ifndef BASE_CALLBACK_H
#define BASE_CALLBACK_H

#include "google/protobuf/stubs/common.h"

namespace google {
namespace protobuf {
namespace internal {
template <typename Arg1, typename Arg2, typename Arg3>
class FunctionClosure3 : public Closure {
 public:
  typedef void (*FunctionType)(Arg1 arg1, Arg2 arg2, Arg3 arg3);

  FunctionClosure3(FunctionType function, bool self_deleting,
                   Arg1 arg1, Arg2 arg2, Arg3 arg3)
    : function_(function), self_deleting_(self_deleting),
      arg1_(arg1), arg2_(arg2), arg3_(arg3) {}
  ~FunctionClosure3() {}

  void Run() {
    bool needs_delete = self_deleting_;  // read in case callback deletes
    function_(arg1_, arg2_, arg3_);
    if (needs_delete) delete this;
  }

 private:
  FunctionType function_;
  bool self_deleting_;
  Arg1 arg1_;
  Arg2 arg2_;
  Arg3 arg3_;
};

template <typename Class, typename Arg1, typename Arg2, typename Arg3>
class MethodClosure3 : public Closure {
 public:
  typedef void (Class::*MethodType)(Arg1 arg1, Arg2 arg2, Arg3 arg3);

  MethodClosure3(Class* object, MethodType method, bool self_deleting,
                 Arg1 arg1, Arg2 arg2, Arg3 arg3)
    : object_(object), method_(method), self_deleting_(self_deleting),
      arg1_(arg1), arg2_(arg2), arg3_(arg3) {}
  ~MethodClosure3() {}

  void Run() {
    bool needs_delete = self_deleting_;  // read in case callback deletes
    (object_->*method_)(arg1_, arg2_, arg3_);
    if (needs_delete) delete this;
  }

 private:
  Class* object_;
  MethodType method_;
  bool self_deleting_;
  Arg1 arg1_;
  Arg2 arg2_;
  Arg3 arg3_;
};
}
// See Closure.
template <typename Class, typename Arg1, typename Arg2, typename Arg3>
inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1, Arg2, Arg3),
                            Arg1 arg1, Arg2 arg2, Arg3 arg3) {
  return new internal::MethodClosure3<Class, Arg1, Arg2, Arg3>(
    object, method, true, arg1, arg2, arg3);
}

// See Closure.
template <typename Class, typename Arg1, typename Arg2, typename Arg3>
inline Closure* NewPermanentCallback(
    Class* object, void (Class::*method)(Arg1, Arg2, Arg3),
    Arg1 arg1, Arg2 arg2, Arg3 arg3) {
  return new internal::MethodClosure3<Class, Arg1, Arg2, Arg3>(
    object, method, false, arg1, arg2, arg3);
}
}
}


using google::protobuf::Closure;
using google::protobuf::NewCallback;
/*
class Callback {
 public:
  Callback();
  virtual ~Callback();
  virtual void Run() = 0;
  virtual bool delete_self();
  void set_delete_self(bool delete_self);

 private:
  bool delete_self_;
};

class Callback0 : public Callback {
 public:
  Callback0(void (*fun)());
  virtual void Run();
 private:
  void (*fun_)();
};

template <class T>
class Callback1 : public Callback {
 public:
  Callback1(void (*fun)(T), T a) : fun_(fun), a_(a) { }
  virtual void Run() { (*fun_)(a_); }
 private:
  void (*fun_)(T);
  T a_;
};

template <class T1, class T2>
class CCallback1 : public Callback {
 public:
  CCallback1(T1* t1, void (T1::*fun)(T2), T2 a) : t1_(t1), fun_(fun), a_(a) { }
  virtual void Run() { (t1_->*fun_)(a_); }
 private:
  T1* t1_;
  void (T1::*fun_)(T2);
  T2 a_;
};

template <class T1, class T2, class T3>
class CCallback2 : public Callback {
 public:
  CCallback2(T1* t1, void (T1::*fun)(T2, T3), T2 a, T3 b) : t1_(t1), fun_(fun), a_(a), b_(b) { }
  virtual void Run() { (t1_->*fun_)(a_, b_); }
 private:
  T1* t1_;
  void (T1::*fun_)(T2, T3);
  T2 a_;
  T3 b_;
};

template <class T1, class T2, class T3, class T4>
class CCallback3 : public Callback {
 public:
  CCallback3(T1* t1, void (T1::*fun)(T2, T3, T4), T2 a, T3 b, T4 c) : t1_(t1), fun_(fun), a_(a), b_(b), c_(c) { }
  virtual void Run() { (t1_->*fun_)(a_, b_, c_); }
 private:
  T1* t1_;
  void (T1::*fun_)(T2, T3, T4);
  T2 a_;
  T3 b_;
  T4 c_;
};

template <class T1, class T2, class T3, class T4, class T5>
class CCallback4 : public Callback {
 public:
  CCallback4(T1* t1, void (T1::*fun)(T2, T3, T4, T5), T2 a, T3 b, T4 c, T5 d) : t1_(t1), fun_(fun), a_(a), b_(b), c_(c), d_(d) { }
  virtual void Run() { (t1_->*fun_)(a_, b_, c_, d_); }
 private:
  T1* t1_;
  void (T1::*fun_)(T2, T3, T4, T5);
  T2 a_;
  T3 b_;
  T4 c_;
  T5 d_;
};



Callback* NewCallback(void (*fun)());

template <class T>
Callback* NewCallback(void (*fun)(T), T var1) {
  return new Callback1<T>(fun, var1);
}

template <class T1, class T2>
Callback* NewCallback(T1* t, void (T1::*fun)(T2), T2 var1) {
  return new CCallback1<T1, T2>(t, fun, var1);
}

template <class T1, class T2, class T3>
Callback* NewCallback(T1* t, void (T1::*fun)(T2, T3), T2 var1, T3 var2) {
  return new CCallback2<T1, T2, T3>(t, fun, var1, var2);
}

template <class T1, class T2, class T3, class T4>
Callback* NewCallback(T1* t, void (T1::*fun)(T2, T3, T4), T2 var1, T3 var2, T4 var3) {
  return new CCallback3<T1, T2, T3, T4>(t, fun, var1, var2, var3);
}

template <class T1, class T2, class T3, class T4, class T5>
Callback* NewCallback(T1* t, void (T1::*fun)(T2, T3, T4, T5), T2 var1, T3 var2, T4 var3, T5 var4) {
  return new CCallback3<T1, T2, T3, T4>(t, fun, var1, var2, var3, var4);
}
*/
#endif
